package com.yang.frost.blueberry.shiro.service.impl;

import com.yang.frost.blueberry.constant.CommonRedisKey;
import com.yang.frost.blueberry.domain.ClientInfo;
import com.yang.frost.blueberry.shiro.jwt.JwtToken;
import com.yang.frost.blueberry.shiro.service.LoginRedisService;
import com.yang.frost.blueberry.shiro.vo.LoginSysUserRedisVo;
import com.yang.frost.blueberry.shiro.vo.LoginSysUserVo;
import com.yang.frost.blueberry.util.ClientInfoUtil;
import com.yang.frost.blueberry.util.HttpServletRequestUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;
import java.util.Set;

/**
 * @author 10296
 * @date 2021/1/25
 * @Description:
 */
@Service
public class LoginRedisServiceImpl implements LoginRedisService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public void cacheLoginInfo(JwtToken jwtToken, LoginSysUserVo loginSysUserVo) {

        if (jwtToken == null) {

            logger.error(">>>>>>>>>>>>>>>>>>>jwtToken 为空 ");
            return;
        }
        if (loginSysUserVo == null) {
            logger.error(">>>>>>>>>>>>>>>>>>>用户信息为空 ");
            return;
        }
        //获取taken
        String token = jwtToken.getToken();
        //获取盐值
        String salt = jwtToken.getSalt();
        //获取用户名信息
        String username = loginSysUserVo.getUsername();
        //获取token md5 值
        String tokenMd5Hex = DigestUtils.md5Hex(token);

        // Redis过期时间与JwtToken过期时间一致
        Duration expireDuration = Duration.ofSeconds(jwtToken.getExpireSecond());

        // 用户客户端信息
        ClientInfo clientInfo = ClientInfoUtil.get(HttpServletRequestUtil.getRequest());

        //对象转换
        LoginSysUserRedisVo loginSysUserRedisVo = new LoginSysUserRedisVo();
        loginSysUserRedisVo.setClientInfo(clientInfo);
        loginSysUserRedisVo.setSalt(salt);
        loginSysUserRedisVo.setUsername(loginSysUserVo.getUsername());
        loginSysUserRedisVo.setDepartmentId(loginSysUserVo.getDepartmentId());
        loginSysUserRedisVo.setDepartmentName(loginSysUserVo.getDepartmentName());
        loginSysUserRedisVo.setGender(loginSysUserVo.getGender());
        loginSysUserRedisVo.setId(loginSysUserVo.getId());
        loginSysUserRedisVo.setNickname(loginSysUserVo.getNickname());
        loginSysUserRedisVo.setPermissionCodes(loginSysUserVo.getPermissionCodes());
        loginSysUserRedisVo.setRoleCode(loginSysUserVo.getRoleCode());
        loginSysUserRedisVo.setRoleId(loginSysUserVo.getRoleId());
        loginSysUserRedisVo.setState(loginSysUserVo.getState());
        loginSysUserRedisVo.setRoleName(loginSysUserVo.getRoleName());

        //缓存Jwt  token 到redis中
        String loginTokenRedisKey = String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5Hex);
        //缓存Redis Token
        redisTemplate.opsForValue().set(loginTokenRedisKey, jwtToken, expireDuration);
        // 2. username:loginSysUserRedisVo
        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_USER, tokenMd5Hex), loginSysUserRedisVo, expireDuration);
        // 3. salt hash,方便获取盐值鉴权
        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_SALT, tokenMd5Hex), salt, expireDuration);
        // 4. login user token
        redisTemplate.opsForValue().set(String.format(CommonRedisKey.LOGIN_USER_TOKEN, username, tokenMd5Hex), loginTokenRedisKey, expireDuration);






    }

    @Override
    public void refreshLoginInfo(String oldToken, String username, JwtToken newJwtToken) {
        // 获取缓存的登录用户信息
        LoginSysUserRedisVo loginSysUserRedisVo = getLoginSysUserRedisVo(username);
        // 删除之前的token信息
        deleteLoginInfo(oldToken, username);
        // 缓存登录信息
        cacheLoginInfo(newJwtToken, loginSysUserRedisVo);
    }

    @Override
    public LoginSysUserRedisVo getLoginSysUserRedisVo(String username) {
        return (LoginSysUserRedisVo) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_USER, username));

    }

    @Override
    public LoginSysUserVo getLoginSysUserRedisVoByToken(String token) {
        //获取token md5 值
        String tokenMd5Hex = DigestUtils.md5Hex(token);

        JwtToken jwtToken = (JwtToken) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5Hex));
        assert jwtToken != null;
        String username = jwtToken.getUsername();
        LoginSysUserRedisVo loginSysUserRedisVo = (LoginSysUserRedisVo) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_USER, tokenMd5Hex));
        //对象转换
        LoginSysUserVo loginSysUserVo = new LoginSysUserVo();

        assert loginSysUserRedisVo != null;
        loginSysUserVo.setUsername(loginSysUserRedisVo.getUsername());
        loginSysUserVo.setDepartmentId(loginSysUserRedisVo.getDepartmentId());
        loginSysUserVo.setDepartmentName(loginSysUserRedisVo.getDepartmentName());
        loginSysUserVo.setGender(loginSysUserRedisVo.getGender());
        loginSysUserVo.setId(loginSysUserRedisVo.getId());
        loginSysUserVo.setNickname(loginSysUserRedisVo.getNickname());
        loginSysUserVo.setPermissionCodes(loginSysUserRedisVo.getPermissionCodes());
        loginSysUserVo.setRoleCode(loginSysUserRedisVo.getRoleCode());
        loginSysUserVo.setRoleId(loginSysUserRedisVo.getRoleId());
        loginSysUserVo.setState(loginSysUserRedisVo.getState());
        loginSysUserVo.setRoleName(loginSysUserRedisVo.getRoleName());
        return loginSysUserVo;

    }

    @Override
    public LoginSysUserVo getLoginSysUserVo(String username) {
        return getLoginSysUserRedisVo(username);
    }

    @Override
    public LoginSysUserVo getLoginSysUserVoByToken(String token) {


        return null;
    }

    @Override
    public String getSalt(String username) {
        return (String) redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_SALT, username));
    }

    @Override
    public void deleteLoginInfo(String token, String username) {
        String tokenMd5 = DigestUtils.md5Hex(token);
        // 1. delete tokenMd5
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5));
        // 2. delete username
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER, tokenMd5));
        // 3. delete salt
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_SALT, tokenMd5));
        // 4. delete user token
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER_TOKEN, username, tokenMd5));
        // 5.  delete token
        redisTemplate.delete(tokenMd5);
    }

    @Override
    public boolean exists(String token) {

        String tokenMd5 = DigestUtils.md5Hex(token);
        Object object = redisTemplate.opsForValue().get(String.format(CommonRedisKey.LOGIN_TOKEN, tokenMd5));
        return object != null;
    }

    @Override
    public void deleteUserAllCache(String username) {
        Set<String> userTokenMd5Set = redisTemplate.keys(String.format(CommonRedisKey.LOGIN_USER_ALL_TOKEN, username));
        if (CollectionUtils.isEmpty(userTokenMd5Set)) {
            return;
        }

        // 1. 删除登录用户的所有token信息
        List<String> tokenMd5List = redisTemplate.opsForValue().multiGet(userTokenMd5Set);
        redisTemplate.delete(tokenMd5List);
        // 2. 删除登录用户的所有user:token信息
        redisTemplate.delete(userTokenMd5Set);
        // 3. 删除登录用户信息
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_USER, username));
        // 4. 删除登录用户盐值信息
        redisTemplate.delete(String.format(CommonRedisKey.LOGIN_SALT, username));
    }


}
